package com.fast.alden.admin.service.impl;

import com.fast.alden.admin.service.SysApiResourceService;
import com.fast.alden.admin.service.SysRoleService;
import com.fast.alden.admin.util.Constants;
import com.fast.alden.common.service.impl.BaseEntityServiceImpl;
import com.fast.alden.data.model.SysApiResource;
import com.fast.alden.data.model.SysApiResourceRole;
import com.fast.alden.data.model.SysRole;
import com.fast.alden.data.repo.SysApiResourceRepository;
import com.fast.alden.data.repo.SysApiResourceRoleRepository;
import jakarta.annotation.Resource;
import jakarta.transaction.Transactional;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
public class SysApiResourceServiceImpl extends BaseEntityServiceImpl<SysApiResource, SysApiResourceRepository> implements SysApiResourceService {
    @Resource
    private SysApiResourceRepository repository;
    @Resource
    private SysApiResourceRoleRepository apiResourceRoleRepository;
    @Resource
    private SysRoleService roleService;
    @Resource
    private CacheManager cacheManager;

    @Override
    protected Class<SysApiResource> getEClass() {
        return SysApiResource.class;
    }

    @Override
    protected SysApiResourceRepository getRepository() {
        return repository;
    }

    @CacheEvict(cacheNames = Constants.CACHE_NAME_API_RESOURCE_LIST, key = Constants.CACHE_KEY_API_RESOURCE_LIST_ALL)
    @Override
    public SysApiResource create(SysApiResource entity) {
        return super.create(entity);
    }

    @Cacheable(cacheNames = Constants.CACHE_NAME_API_RESOURCE_LIST, key = Constants.CACHE_KEY_API_RESOURCE_LIST_ALL)
    @Override
    public List<SysApiResource> list() {
        return super.list();
    }

    @CacheEvict(cacheNames = Constants.CACHE_NAME_API_RESOURCE_LIST, key = Constants.CACHE_KEY_API_RESOURCE_LIST_ALL)
    @Override
    public SysApiResource update(SysApiResource entity) {
        return super.update(entity);
    }

    @CacheEvict(cacheNames = Constants.CACHE_NAME_API_RESOURCE_LIST, key = Constants.CACHE_KEY_API_RESOURCE_LIST_ALL)
    @Transactional
    @Override
    public List<SysApiResource> remove(List<Long> ids) {
        List<SysApiResource> resources = super.remove(ids);

        // 删除资源-角色关联数据
        apiResourceRoleRepository.deleteByApiResourceIdIn(ids);

        return resources;
    }

    @Override
    @Transactional
    public void assign(Long roleId, List<Long> apiResourceIds) {
        SysRole role = roleService.retrieveWithException(roleId);

        List<SysApiResourceRole> existList = apiResourceRoleRepository.findAllByRoleIdIsAndApiResourceIdIn(roleId, apiResourceIds);
        List<Long> existApiResourceIds = existList.stream().map(SysApiResourceRole::getApiResourceId).toList();

        List<Long> toAddApiResourceIds = apiResourceIds.stream().filter(it -> !existApiResourceIds.contains(it)).toList();

        if (toAddApiResourceIds.isEmpty()) {
            return;
        }

        List<SysApiResourceRole> toAddList = toAddApiResourceIds.stream().map(it -> {
            SysApiResourceRole apiResourceRole = new SysApiResourceRole();
            apiResourceRole.setRoleId(roleId);
            apiResourceRole.setApiResourceId(it);
            return apiResourceRole;
        }).toList();

        apiResourceRoleRepository.saveAll(toAddList);
    }

    @Override
    @Transactional
    public void cancelAssign(Long roleId, List<Long> apiResourceIds) {
        SysRole role = roleService.retrieveWithException(roleId);

        List<SysApiResourceRole> existList = apiResourceRoleRepository.findAllByRoleIdIsAndApiResourceIdIn(roleId, apiResourceIds);
        if (existList.isEmpty()) {
            return;
        }

        apiResourceRoleRepository.deleteAll(existList);
    }

    @Override
    public List<SysApiResourceRole> findApiResourceRolesByRoleIdIn(List<Long> roleIds) {
        return apiResourceRoleRepository.findAllByRoleIdIn(roleIds);
    }

    @Override
    public List<SysApiResourceRole> findApiResourceRolesByApiResourceIdIn(List<Long> apiResourceIds) {
        return apiResourceRoleRepository.findAllByApiResourceIdIn(apiResourceIds);
    }

    @Override
    public List<SysApiResource> findApiResourcesByRoleId(Long roleId) {
        List<SysApiResource> resources = new ArrayList<>();

        // 只需要登录即可访问的API资源
        List<SysApiResource> withoutPermissions = repository.findAllByRequireLoginIsFalseOrRequireLoginIsTrueAndRequirePermissionsIsFalse();
        resources.addAll(withoutPermissions);

        // 指定角色可访问的API资源
        List<SysApiResourceRole> apiResourceRoles = this.findApiResourceRolesByRoleIdIn(List.of(roleId));
        List<Long> apiResourceIds = apiResourceRoles.stream().map(SysApiResourceRole::getApiResourceId).toList();

        resources.addAll(this.list(apiResourceIds));

        return resources;
    }
}
